<?php

declare(strict_types=1);

namespace app\model\oa;

use think\Model;

/**
 * 消息接收模型
 * @package app\model\oa
 */
class Msg extends Model
{
    /**
     * 表名（不含前缀）
     * @var string
     */
    protected $name = 'msg';

    /**
     * 主键
     * @var string
     */
    protected $pk = 'id';

    /**
     * 自动时间戳
     * @var bool
     */
    protected $autoWriteTimestamp = false;

    /**
     * 创建时间字段
     * @var string
     */
    protected $createTime = 'create_time';

    /**
     * 更新时间字段
     * @var string
     */
    protected $updateTime = 'update_time';

    /**
     * 软删除字段
     * @var string
     */
    protected $deleteTime = 'delete_time';

    /**
     * 是否星标常量
     */
    const IS_STAR_YES = 1; // 星标
    const IS_STAR_NO = 0;  // 非星标

    /**
     * 字段类型映射
     * @var array
     */
    protected $schema = [
        'id' => 'int',
        'title' => 'string',
        'template' => 'string',
        'content' => 'string',
        'file_ids' => 'string',
        'from_uid' => 'int',
        'to_uid' => 'int',
        'message_id' => 'int',
        'msg_id' => 'int',
        'is_star' => 'int',
        'read_time' => 'int',
        'create_time' => 'int',
        'update_time' => 'int',
        'delete_time' => 'int',
        'clear_time' => 'int',
        'action_id' => 'int',
    ];

    /**
     * 关联发送人
     * @return \think\model\relation\HasOne
     */
    public function sender()
    {
        return $this->hasOne('app\model\oa\Admin', 'id', 'from_uid')
            ->field('id,username,nickname,avatar');
    }

    /**
     * 关联接收人
     * @return \think\model\relation\HasOne
     */
    public function receiver()
    {
        return $this->hasOne('app\model\oa\Admin', 'id', 'to_uid')
            ->field('id,username,nickname,avatar');
    }

    /**
     * 关联原始消息
     * @return \think\model\relation\HasOne
     */
    public function originalMessage()
    {
        return $this->hasOne('app\model\oa\Message', 'id', 'message_id');
    }

    /**
     * 关联转发/回复消息
     * @return \think\model\relation\HasOne
     */
    public function relatedMessage()
    {
        return $this->hasOne('app\model\oa\Message', 'id', 'msg_id');
    }

    /**
     * 关联消息模板
     * @return \think\model\relation\HasOne
     */
    public function templateInfo()
    {
        return $this->hasOne('app\model\oa\Template', 'name', 'template')
            ->field('id,title,name,types,remark');
    }

    /**
     * 获取用户收件箱
     * @param int $userId
     * @return \think\Paginator
     */
    public static function getInbox(int $userId)
    {
        return self::where('to_uid', $userId)
            ->where('delete_time', 0)
            ->order('create_time', 'desc')
            ->paginate();
    }

    /**
     * 获取用户已发送消息
     * @param int $userId
     * @return \think\Paginator
     */
    public static function getSent(int $userId)
    {
        return self::where('from_uid', $userId)
            ->where('delete_time', 0)
            ->order('create_time', 'desc')
            ->paginate();
    }

    /**
     * 获取用户星标消息
     * @param int $userId
     * @return \think\Paginator
     */
    public static function getStarred(int $userId)
    {
        return self::where('to_uid', $userId)
            ->where('is_star', self::IS_STAR_YES)
            ->where('delete_time', 0)
            ->order('create_time', 'desc')
            ->paginate();
    }

    /**
     * 获取用户未读消息
     * @param int $userId
     * @return \think\Paginator
     */
    public static function getUnread(int $userId)
    {
        return self::where('to_uid', $userId)
            ->where('read_time', 0)
            ->where('delete_time', 0)
            ->order('create_time', 'desc')
            ->paginate();
    }

    /**
     * 获取用户已读消息
     * @param int $userId
     * @return \think\Paginator
     */
    public static function getRead(int $userId)
    {
        return self::where('to_uid', $userId)
            ->where('read_time', '>', 0)
            ->where('delete_time', 0)
            ->order('read_time', 'desc')
            ->paginate();
    }

    /**
     * 标记为已读
     * @return bool
     */
    public function markAsRead(): bool
    {
        if ($this->read_time === 0) {
            return $this->save(['read_time' => time()]);
        }
        return true;
    }

    /**
     * 标记为未读
     * @return bool
     */
    public function markAsUnread(): bool
    {
        return $this->save(['read_time' => 0]);
    }

    /**
     * 切换星标状态
     * @return bool
     */
    public function toggleStar(): bool
    {
        $newStatus = $this->is_star === self::IS_STAR_YES ? self::IS_STAR_NO : self::IS_STAR_YES;
        return $this->save(['is_star' => $newStatus]);
    }

    /**
     * 是否已读
     * @return bool
     */
    public function isRead(): bool
    {
        return $this->read_time > 0;
    }

    /**
     * 是否未读
     * @return bool
     */
    public function isUnread(): bool
    {
        return $this->read_time === 0;
    }

    /**
     * 是否星标
     * @return bool
     */
    public function isStarred(): bool
    {
        return $this->is_star === self::IS_STAR_YES;
    }

    /**
     * 获取附件ID数组
     * @return array
     */
    public function getFileIds(): array
    {
        $ids = $this->file_ids ?? '';
        if (empty($ids)) {
            return [];
        }
        return array_filter(array_map('intval', explode(',', $ids)));
    }

    /**
     * 获取阅读时间格式化
     * @return string
     */
    public function getReadTimeTextAttr(): string
    {
        return $this->read_time > 0 ? date('Y-m-d H:i:s', $this->read_time) : '未读';
    }

    /**
     * 星标状态描述获取器
     * @param int $value
     * @return string
     */
    public function getStarTextAttr(int $value): string
    {
        return $value === self::IS_STAR_YES ? '星标' : '普通';
    }

    /**
     * 接收人搜索器
     * @param \think\db\Query $query
     * @param mixed $value
     */
    public function searchToUidAttr($query, $value)
    {
        if ($value !== '') {
            $query->where('to_uid', $value);
        }
    }

    /**
     * 发送人搜索器
     * @param \think\db\Query $query
     * @param mixed $value
     */
    public function searchFromUidAttr($query, $value)
    {
        if ($value !== '') {
            $query->where('from_uid', $value);
        }
    }

    /**
     * 星标状态搜索器
     * @param \think\db\Query $query
     * @param mixed $value
     */
    public function searchIsStarAttr($query, $value)
    {
        if ($value !== '') {
            $query->where('is_star', $value);
        }
    }

    /**
     * 阅读状态搜索器
     * @param \think\db\Query $query
     * @param mixed $value
     */
    public function searchReadStatusAttr($query, $value)
    {
        if ($value === 'read') {
            $query->where('read_time', '>', 0);
        } elseif ($value === 'unread') {
            $query->where('read_time', 0);
        }
    }

    /**
     * 标题搜索器
     * @param \think\db\Query $query
     * @param mixed $value
     */
    public function searchTitleAttr($query, $value)
    {
        if ($value !== '') {
            $query->whereLike('title', '%' . $value . '%');
        }
    }

    /**
     * 内容搜索器
     * @param \think\db\Query $query
     * @param mixed $value
     */
    public function searchContentAttr($query, $value)
    {
        if ($value !== '') {
            $query->whereLike('content', '%' . $value . '%');
        }
    }

    /**
     * 创建时间范围搜索器
     * @param \think\db\Query $query
     * @param array $value
     */
    public function searchCreateTimeAttr($query, array $value)
    {
        if (!empty($value[0])) {
            $query->where('create_time', '>=', strtotime($value[0]));
        }
        if (!empty($value[1])) {
            $query->where('create_time', '<=', strtotime($value[1]));
        }
    }

    /**
     * 获取用户消息统计
     * @param int $userId
     * @return array
     */
    public static function getUserStats(int $userId): array
    {
        $total = self::where('to_uid', $userId)->where('delete_time', 0)->count();
        $unread = self::where('to_uid', $userId)->where('read_time', 0)->where('delete_time', 0)->count();
        $starred = self::where('to_uid', $userId)->where('is_star', self::IS_STAR_YES)->where('delete_time', 0)->count();
        
        return [
            'total' => $total,
            'unread' => $unread,
            'starred' => $starred,
            'read' => $total - $unread,
        ];
    }
}